﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace COFE.Core.Actions
{
    /// <summary>
    /// A WorkBase that allow chaining a number of actions and running them together.
    /// </summary>
    public class ActionWork : WorkBase
    {
        private class ActionWorkProgressProxy : IWorkProgress
        {
            public ActionWorkProgressProxy(ActionWork parentAction, int totalActions)
            {
                _parentAction = parentAction;
                _totalActions = totalActions;
            }

            public IWork Work { get { return _parentAction; } }


            #region Methods

            public bool OnWorkMessage(WorkMessageEventArgs e)
            {
                return _parentAction.OnWorkMessage(e);
            }

            public bool OnWorkProgress(WorkProgressEventArgs e)
            {
                if (e.CurrentProgress != -1)
                {

                    var currentProgress =
                        e.TotalProgress != -1 ? (float)e.CurrentProgress / (float)e.TotalProgress * 100.0 :
                                (float)e.CurrentProgress;
                    var adjustedProgress = (currentProgress + (_actionId * 100.0)) / ((float)_totalActions * 100.0) * 100.0;

                    return _parentAction.OnWorkProgress(
                        new WorkProgressEventArgs(Work, (int)adjustedProgress, 100, e.File));
                }
                else
                    return _parentAction.OnWorkProgress(e);
            }

            public void CheckPause()
            {
                _parentAction.CheckPause();
            }

            #endregion

            #region Data

            private ActionWork _parentAction;
            private int _actionId, _totalActions;

            #endregion

            #region Public Properties

            #endregion


        }

        #region Constructor

        public ActionWork(Guid id, IEntryList input,
            Tuple<object, string>[] actions)
            : base(id)
        {
            _input = input;
            _actions = actions;
        }


        public ActionWork(Guid id, IEntryList input,
            Tuple<object, string> action)
            : this(id, input, new Tuple<object, string>[] { action })
        {

        }


        protected ActionWork(Guid id, IEntryList input)
            : base(id)
        {
            _input = input;
            //_actions assigned by implementers.
        }

        #endregion

        #region Methods

        protected override void DoWork()
        {
            IEntryList currentInput = _input;
            int currentActionId = 0;

            while (currentActionId < _actions.Length)
            {
                OnWorkProgress(new WorkProgressEventArgs(Work, currentActionId, _actions.Length, null));
                var currentAction = _actions[currentActionId];
                if (!currentInput.HasAction(currentAction.Item1))
                    throw new NotSupportedException(currentAction.Item1.ToString() + " is not supported.");

                var actionFunc = currentInput.GetAction(currentAction.Item1);
                currentInput = actionFunc(currentInput, currentAction.Item2,
                    new ActionWorkProgressProxy(this, _actions.Length));

                currentActionId++;
            }
        }

        #endregion

        #region Data

        private Tuple<object, string>[] _actions;
        private IEntryList _input;

        #endregion

        #region Public Properties


        public Tuple<object, string>[] Actions
        {
            get { return _actions; }
            protected set { _actions = value; }
        }
        public IEntryList Input { get { return _input; } }

        #endregion
    }
}
